package math;

import java.util.List;
import java.util.ArrayList;
import java.util.Random;

public class MonteCarloIntegration {
	private static final double A = 1., B = 1.;
	private static Random dice = new Random();
	
	
	private static List<Double> xValues = new ArrayList<Double>();
	private static List<Double> distances = new ArrayList<Double>();
	private static List<Double> values = new ArrayList<Double>();
	private static final double START = 0., STEP_SIZE = 1;
	private static final int ITERATIONS = 2000;

	/**
	 * 1.3988353689575115 1.4011787627976715
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
//		dice.setSeed(1L);
		for(int i=0; i<1; i++){
			doSteps();
			integrate();
		}
		
	}

	private static void integrate() {
		values = new ArrayList<Double>();
		for (int i = 0; i < xValues.size(); i++) {
			values.add(fun(xValues.get(i)));
		}
		System.out.println("\nergebnis: "+Statistics.mean(values));
	}

	private static void doSteps() {
		xValues = new ArrayList<Double>();
		double xOld = START;
		double pOld = p(START);
		for (int i = 0; i < ITERATIONS;) {
			double step = dice.nextGaussian()*STEP_SIZE;
			double xTest = step + xOld;
			double pTest = p(xTest);
			double q = pTest / pOld;
			if(q>1){
				distances.add(step);
				xValues.add(xTest);
				xOld = xTest;
				pOld = p(xTest);
				i=xValues.size();
				continue;
			}
			else if(rand()<q){
				distances.add(step);
				xValues.add(xTest);
				xOld = xTest;
				pOld = p(xTest);
				i=xValues.size();
				continue;
			}
		}
//		for(int i=0; i<ITERATIONS; i++){
//			steps.add(dice.nextGaussian());
//		}
		System.out.println("Steps: max"+Statistics.max(distances)+"  min: "+Statistics.min(distances));
		System.out.println("pos: max" + Statistics.max(xValues) + "  min: " + Statistics.min(xValues) + " mean: "
				+ Statistics.mean(xValues)+ "  STDABW: "+Statistics.stddev(xValues));
	}

	private static double rand() {
//		return Math.random();
		return dice.nextDouble();
	}

	/**
	 * wahrscheinlichkeitsdichte
	 * 
	 * @return
	 */
	private static double p(double x) {
		 return Math.sqrt(B/Math.PI)*Math.exp(-1*B*x*x);
	}

	private static double fun(double x) {
		return Math.cos(A * x)*Math.sqrt(Math.PI /B );
	}
}
